﻿using System.Collections.Generic;
using System.Linq;
using NoteHelper.IBusiness;
using IBatisNet.DataMapper;
using IBatisNet.DataMapper.MappedStatements;
using IBatisNet.DataMapper.Scope;
using NoteHelper.Model;
using System.ComponentModel.DataAnnotations;
using System.Data;
using NoteHelper.Business.IbatisImpl.Base;

namespace NoteHelper.Business.IbatisImpl
{
    public class ManagerBase<T> : IServiceBase<T> where T : class
    {
        #region constructor

        protected ISqlMapper Mapper { get { return SqliteMapper.Instance(); } }
        protected log4net.ILog MyLogger { get; set; }

        protected ManagerBase()
        {
            MyLogger = log4net.LogManager.GetLogger(GetType());
        }

        #endregion constructor

        private string Name
        {
            get { return typeof(T).Name; }
        }

        public virtual T Get(object id)
        {
            string statementName = string.Format("Get{0}", Name);
            LogRuntimeSql(statementName, id);
            var entity = Mapper.QueryForObject(statementName, id) as T;
            return entity;
        }

        public int GetCount()
        {
            string statementName = string.Format("{0}Count", Name);
            LogRuntimeSql(statementName, null);
            return (int)Mapper.QueryForObject(statementName, null);
        }

        [Transaction]
        public virtual object Add(T entity)
        {
            Validate(entity);
            string statementName = string.Format("Insert{0}", Name);
            LogRuntimeSql(statementName, entity);
            return Mapper.Insert(statementName, entity);
        }

        [Transaction]
        public virtual int Update(T entity)
        {
            Validate(entity);
            string statementName = string.Format("Update{0}", Name);
            LogRuntimeSql(statementName, entity);
            return Mapper.Update(statementName, entity);
        }

        [Transaction]
        public virtual int Delete(object id)
        {
            string statementName = string.Format("Delete{0}", Name);
            LogRuntimeSql(statementName, id);
            return Mapper.Delete(statementName, id);
        }

        public virtual IList<T> GetAll()
        {
            string statementName = string.Format("GetAll{0}", Name);
            LogRuntimeSql(statementName, null);
            return Mapper.QueryForList<T>(statementName, null);
        }

        private static IDialect dialect = new SQLiteDialect();
        public virtual void LogRuntimeSql(string statementName, object paramObject)
        {
            if (MyLogger.IsDebugEnabled)
            {
                IMappedStatement statement = Mapper.GetMappedStatement(statementName);
                if (!Mapper.IsSessionStarted)
                {
                    Mapper.OpenConnection();
                }
                RequestScope scope = statement.Statement.Sql.GetRequestScope(statement, paramObject, Mapper.LocalSession);
                MyLogger.Debug(scope.PreparedStatement.PreparedSql);
            }
        }

        private void Validate(T entity)
        {
            if (entity == null)
            {
                ValidationResult v = new ValidationResult("实体参数entity不应该为NULL！");
                throw new ValidationException();
            }
            else
            {
                var lst = DataAnnotationHelper.GetValidationResults(entity);
                if (lst.Count == 0)
                    return;

                var r = string.Join("\r\n",
                    lst.Select(t => string.Format("Error Message:{0}.{1}", Name, t.ErrorMessage)));
                throw new ValidationException(r);
            }
        }

        public DataTable QueryForDataTable(string statementName, object parameterObject)
        {
            bool isSessionLocal = false;
            ISqlMapSession session = Mapper.LocalSession;
            DataTable dataTable = null;
            if (session == null)
            {
                session = Mapper.CreateSqlMapSession();
                isSessionLocal = true;
            }
            try
            {
                IMappedStatement statement = Mapper.GetMappedStatement(statementName);
                dataTable = new DataTable(statementName);
                RequestScope request = statement.Statement.Sql.GetRequestScope(statement, parameterObject, session);
                statement.PreparedCommand.Create(request, session, statement.Statement, parameterObject);
                using (request.IDbCommand)
                {
                    dataTable.Load(request.IDbCommand.ExecuteReader());
                }
            }
            catch
            {
                throw;
            }
            finally
            {
                if (isSessionLocal)
                {
                    session.CloseConnection();
                }
            }
            return dataTable;
        }
    }
}
